package com.streambolics.std;

public class StringExtensions
{
    /**
     * The contents of s after the tag, or the empty string if the tag is not
     * found.
     * 
     * @param s
     *            The string to search for
     * @param tag
     *            The separator tag
     * 
     * @return All characters after the first occurrence of the tag, or null if
     *         the tag was not found.
     */
    public static String after (String s, String tag)
    {
        int index = s.indexOf (tag);
        if (index < 0)
        {
            return null;
        }
        else
        {
            return s.substring (index + tag.length ());
        }
    }

    public static String before (String s, String tag)
    {
        int index = s.indexOf (tag);
        if (index < 0)
        {
            return null;
        }
        else
        {
            return s.substring (0, index);
        }
    }

    /**
     * All characters between two separators.
     * 
     * @param s
     *            The string to scan.
     * @param first
     *            The first separator.
     * @param last
     *            The last separator.
     * 
     * @return All characters of s after the first occurrence of first, and
     *         before the first occurrence of last after first, or null if
     *         either first or last was not found.
     */
    public static String between (String s, String first, String last)
    {
        int firstIndex = s.indexOf (first);
        if (firstIndex >= 0)
        {
            s = s.substring (firstIndex + first.length ());
        }
        else
        {
            return null;
        }
        int lastIndex = s.indexOf (last);
        if (lastIndex >= 0)
        {
            return s.substring (0, lastIndex);
        }
        else
        {
            return null;
        }
    }

    public static int countNonBlank (String... aStrings)
    {
        int n = 0;
        for (String s : aStrings)
        {
            if (isNotEmpty (s))
            {
                n++;
            }
        }
        return n;
    }

    /**
     * Extracts an exact substring from a string.
     * 
     * <p>
     * The "exact" word means that the extracted substring is guaranteed to be
     * exactly aLength characters long, even if aFirst and aLength indicate
     * positions outside the range of the input string.
     * </p>
     * 
     * @param aString
     *            The string from where a substring will be extracted.
     * @param aFirst
     *            The index of the first character to extract. Zero is the first
     *            character of the string. Negative values are allowed, and will
     *            return that number of spaces in front.
     * @param aLength
     *            The length of the substring to be returned. It is guaranteed
     *            that the string will be exactly of this size. Zero will return
     *            the empty string. Negative values are not allowed.
     * @return A string of exactly aLength characters. If there are not enough
     *         characters in the input string, spaces are added to fill the
     *         missing positions. Spaces are added at the appropriate place: at
     *         the beginning if trying to extract characters before index 0
     *         (this of course requires that aFirst is negative) and at the end
     *         if trying to extract characters after the end of the input
     *         string.
     */

    public static String exactSubString (String aString, int aFirst, int aLength)
    {
        String prefix = "";
        String suffix = "";

        if (aLength < 0)
        {
            throw new IllegalArgumentException ();
        }

        if (aLength == 0)
        {
            return "";
        }

        if (isEmpty (aString) || aFirst + aLength <= 0 || aFirst >= aString.length ())
        {
            return spaces (aLength);
        }

        if (aFirst < 0)
        {
            prefix = spaces (-aFirst);
            aLength += aFirst;
            aFirst = 0;
        }

        int overflow = aFirst + aLength - aString.length ();

        if (overflow > 0)
        {
            suffix = spaces (overflow);
            aLength -= overflow;
        }

        return prefix + aString.substring (aFirst, aFirst + aLength) + suffix;
    }

    public static String format (String aFormat, FieldExtractor aFields)
    {
        StringBuilder sb = new StringBuilder ();
        int n;
        char c;
        int i = 0;

        while (i < aFormat.length ())
        {
            c = aFormat.charAt (i);
            if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
            {
                n = 1;
                i++;
                while (i < aFormat.length () && aFormat.charAt (i) == c)
                {
                    n++;
                    i++;
                }
                sb.append (aFields.extract (c, n));
            }
            else
            {
                sb.append (c);
                i++;
            }

        }
        return sb.toString ();
    }

    /**
     * Whether a string is the empty string.
     * 
     * @param s
     *            The string to check.
     * @return true if s is null or the empty string. False otherwise.
     */

    public static boolean isEmpty (String s)
    {

        return s == null || s.equals ("");
    }

    public static boolean isNotEmpty (String s)
    {
        return s != null && !s.equals ("");
    }

    public static String spaces (int aLength)
    {
        return String.format ("%*s", aLength, "");
    }

}
